package Core;

import java.util.Random;
import java.util.*;

public class GraphGenerator {
	
	// ICA and ICB represent the Information Content of corresponding
	// nodes in topic A and B respectively 
	
	Vector<Integer> ICA,ICB;
	int ratioA,ratioB,size,limit;
	double density;
	int p_A, p_B;
	Random rand;
	Vector<Vector<IntegerPair>> AdjListA,AdjListB;
	
	public GraphGenerator(int s,double d,int r_A,int r_B,int pA,int pB) {
		rand = new Random();
		ratioA = r_A;
		ratioB = r_B;
		p_A = pA;
		p_B = pB;
		density = d;
		size = s;
		
		// To assign information contents
		//limit = (ratioA + ratioB)*(ratioA + ratioB);
		limit = 100;
		createGraph(size,density,ratioA,ratioB,p_A,p_B);
	}
	
	// size - size of the graph to be generated
	// density - sparseness or density of edges
	// ratioA,ratioB - Diversity of opinion
	void initList(int size) {
		AdjListA = new Vector<Vector<IntegerPair>>();
		AdjListB = new Vector<Vector<IntegerPair>>();
		makeLists(size);
	}
	
	void makeLists(int size) {
		int i;
		for(i=0;i<size;i++) {
			AdjListA.add(new Vector<IntegerPair>());
			AdjListB.add(new Vector<IntegerPair>());
		}
	}
	
	void createGraph(int size,double density,int ratioA,int ratioB, int p_A,int p_B) {
		ICA = new Vector<Integer>();
		ICB = new Vector<Integer>();
		int i,numE;
		// Make the adjacency list framework
		initList(size);
		
		// number of edges to be generated
		numE = numEdges(size,density) + 1;
		
		// Creating vertices but not introducing any connections b/w them
		for(i=0;i<size;i++) {
			// assigning weights to the vertices
			ICA.add(1 + ratioA * (rand.nextInt(limit)));
			ICB.add(1 + ratioB * (rand.nextInt(limit)));
		}
	
		makeConnections(numE);
	}
	
	public void makeConnections(int numE) {
		int i,v1,v2;
		double p1,p2;
		
		for(i = 0; i<numE; i++) {
			v1 = rand.nextInt(size);
			v2 = rand.nextInt(size);
			
			// to make sure no vertex links back to itself and no duplicate edges are allowed
			while(v1 == v2 || !notPresent(v1,v2)) {
				v1 = rand.nextInt(size);
				v2 = rand.nextInt(size);
			}
			
			// Assigning probabilities
			// Ensured that max value of probabilities is 1 and minimum is the lower bound specified
			p1 = (double) (p_A/100.0 + (rand.nextInt((100 - p_A)))/100.0);
			p2 = (double) (p_A/100.0 + (rand.nextInt((100 - p_A)))/100.0);
			
			// establish connection between v1&v2 and assign probability
			AdjListA.get(v1).add(new IntegerPair(v2,p1));
			AdjListB.get(v1).add(new IntegerPair(v2,p2));
		}
	}
	
	public boolean notPresent(int v1,int v2) {
		
		for(IntegerPair i:AdjListA.get(v1)) {
			if(i.first() == v2)
				return false;
		}
		
		return true;
	}
	
	public int numEdges(int s,double d) {
		return (int)((s*(s-1)/2)*d);
	}
	
	public void increaseSize(int increaseAmt) {
		int i;
		
		makeLists(increaseAmt);
		size += increaseAmt;
		
		int numE = numEdges(increaseAmt,density) + 1;

		for(i = increaseAmt;i > 0; i--) {
			// assigning weights to the vertices
			ICA.add(1 + ratioA * (rand.nextInt(limit)));
			ICB.add(1 + ratioB * (rand.nextInt(limit)));
		}
		
		makeConnections(numE);
	}
	
	public Vector<Integer> getICA() {
		return ICA;
	}
	
	public Vector<Integer> getICB() {
		return ICB;
	}
	
	public Vector<Vector<IntegerPair>> getListA() {
		return AdjListA;
	}
	
	public Vector<Vector<IntegerPair>> getListB() {
		return AdjListB;
	}
}
